agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v5 1/3] Adding per backend commit and rollback counters
682+ messages / 2 participants
[nested] [flat]

* [PATCH v5 1/3] Adding per backend commit and rollback counters
@ 2025-08-04 08:14  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Bertrand Drouvot @ 2025-08-04 08:14 UTC (permalink / raw)

It relies on the existing per backend statistics that has been added in
9aea73fc61d. The new pending counters are updated when the database ones are
flushed (to reduce the overhead of incrementing new counters).
---
 src/backend/utils/activity/pgstat_backend.c  | 42 +++++++++++++++++++-
 src/backend/utils/activity/pgstat_database.c |  7 ++++
 src/include/pgstat.h                         | 15 +++++++
 src/include/utils/pgstat_internal.h          |  3 +-
 4 files changed, 65 insertions(+), 2 deletions(-)
  74.4% src/backend/utils/activity/
   7.8% src/include/utils/
  17.7% src/include/

diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c
index 7727fed3bda..42bfb9cd38f 100644
--- a/src/backend/utils/activity/pgstat_backend.c
+++ b/src/backend/utils/activity/pgstat_backend.c
@@ -37,7 +37,7 @@
  * reported within critical sections so we use static memory in order to avoid
  * memory allocation.
  */
-static PgStat_BackendPending PendingBackendStats;
+PgStat_BackendPending PendingBackendStats;
 static bool backend_has_iostats = false;
 
 /*
@@ -48,6 +48,11 @@ static bool backend_has_iostats = false;
  */
 static WalUsage prevBackendWalUsage;
 
+/*
+ * For backend commit and rollback statistics.
+ */
+bool		backend_has_xactstats = false;
+
 /*
  * Utility routines to report I/O stats for backends, kept here to avoid
  * exposing PendingBackendStats to the outside world.
@@ -261,6 +266,34 @@ pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref)
 	prevBackendWalUsage = pgWalUsage;
 }
 
+/*
+ * Flush out locally pending backend transaction statistics.  Locking is managed
+ * by the caller.
+ */
+static void
+pgstat_flush_backend_entry_xact(PgStat_EntryRef *entry_ref)
+{
+	PgStatShared_Backend *shbackendent;
+
+	/*
+	 * This function can be called even if nothing at all has happened for
+	 * transaction statistics.  In this case, avoid unnecessarily modifying
+	 * the stats entry.
+	 */
+	if (!backend_has_xactstats)
+		return;
+
+	shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
+
+	shbackendent->stats.xact_commit += PendingBackendStats.pending_xact_commit;
+	shbackendent->stats.xact_rollback += PendingBackendStats.pending_xact_rollback;
+
+	PendingBackendStats.pending_xact_commit = 0;
+	PendingBackendStats.pending_xact_rollback = 0;
+
+	backend_has_xactstats = false;
+}
+
 /*
  * Flush out locally pending backend statistics
  *
@@ -285,6 +318,10 @@ pgstat_flush_backend(bool nowait, uint32 flags)
 		pgstat_backend_wal_have_pending())
 		has_pending_data = true;
 
+	/* Some transaction data pending? */
+	if ((flags & PGSTAT_BACKEND_FLUSH_XACT) && backend_has_xactstats)
+		has_pending_data = true;
+
 	if (!has_pending_data)
 		return false;
 
@@ -300,6 +337,9 @@ pgstat_flush_backend(bool nowait, uint32 flags)
 	if (flags & PGSTAT_BACKEND_FLUSH_WAL)
 		pgstat_flush_backend_entry_wal(entry_ref);
 
+	if (flags & PGSTAT_BACKEND_FLUSH_XACT)
+		pgstat_flush_backend_entry_xact(entry_ref);
+
 	pgstat_unlock_entry(entry_ref);
 
 	return false;
diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c
index 933dcb5cae5..218ff5e653c 100644
--- a/src/backend/utils/activity/pgstat_database.c
+++ b/src/backend/utils/activity/pgstat_database.c
@@ -352,6 +352,13 @@ pgstat_update_dbstats(TimestampTz ts)
 	dbentry->blk_read_time += pgStatBlockReadTime;
 	dbentry->blk_write_time += pgStatBlockWriteTime;
 
+	/* Do the same for backend stats */
+	PendingBackendStats.pending_xact_commit += pgStatXactCommit;
+	PendingBackendStats.pending_xact_rollback += pgStatXactRollback;
+
+	backend_has_xactstats = true;
+	pgstat_report_fixed = true;
+
 	if (pgstat_should_report_connstat())
 	{
 		long		secs;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 8e3549c3752..5d73c4dfbcf 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -523,6 +523,8 @@ typedef struct PgStat_Backend
 	TimestampTz stat_reset_timestamp;
 	PgStat_BktypeIO io_stats;
 	PgStat_WalCounters wal_counters;
+	PgStat_Counter xact_commit;
+	PgStat_Counter xact_rollback;
 } PgStat_Backend;
 
 /* ---------
@@ -535,6 +537,12 @@ typedef struct PgStat_BackendPending
 	 * Backend statistics store the same amount of IO data as PGSTAT_KIND_IO.
 	 */
 	PgStat_PendingIO pending_io;
+
+	/*
+	 * Transaction statistics pending flush.
+	 */
+	PgStat_Counter pending_xact_commit;
+	PgStat_Counter pending_xact_rollback;
 } PgStat_BackendPending;
 
 /*
@@ -844,6 +852,13 @@ extern PGDLLIMPORT int pgstat_track_functions;
 extern PGDLLIMPORT int pgstat_fetch_consistency;
 
 
+/*
+ * Variables in pgstat_backend.c
+ */
+
+extern PGDLLIMPORT PgStat_BackendPending PendingBackendStats;
+extern PGDLLIMPORT bool backend_has_xactstats;
+
 /*
  * Variables in pgstat_bgwriter.c
  */
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index eed4c6b359c..8077c65e938 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -707,7 +707,8 @@ extern void pgstat_archiver_snapshot_cb(void);
 /* flags for pgstat_flush_backend() */
 #define PGSTAT_BACKEND_FLUSH_IO		(1 << 0)	/* Flush I/O statistics */
 #define PGSTAT_BACKEND_FLUSH_WAL   (1 << 1) /* Flush WAL statistics */
-#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL)
+#define PGSTAT_BACKEND_FLUSH_XACT   (1 << 2)	/* Flush xact statistics */
+#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL | PGSTAT_BACKEND_FLUSH_XACT)
 
 extern bool pgstat_flush_backend(bool nowait, uint32 flags);
 extern bool pgstat_backend_flush_cb(bool nowait);
-- 
2.34.1


--uN5gGi2rtCNSVbpC
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v5-0002-Adding-XID-generation-count-per-backend.patch"



^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--






^ permalink  raw  reply  [nested|flat] 682+ messages in thread

* [PATCH v1 3/3] LO frontend PQexecParams
@ 2026-05-26 16:12  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 682+ messages in thread

From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw)

---
 src/interfaces/libpq/fe-connect.c |   1 -
 src/interfaces/libpq/fe-lobj.c    | 236 ++++--------------------------
 src/interfaces/libpq/libpq-int.h  |   1 -
 3 files changed, 26 insertions(+), 212 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 01c9735f276..9f6aa01dc0e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn)
 	conn->in_hot_standby = PG_BOOL_UNKNOWN;
 	conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
 	conn->sversion = 0;
-	conn->lobjprepared = false;
 
 	/* Reset assorted other per-connection state */
 	conn->last_sqlstate[0] = '\0';
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 41573c22c80..17c1d699a48 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -41,89 +41,6 @@
 
 #define LO_BUFSIZE		  8192
 
-typedef struct PGlobjfuncs
-{
-	char	   *name;
-	char	   *args;
-	int			nargs;
-	int			version;
-} PGlobjfuncs;
-
-static const PGlobjfuncs lobjfuncs[] =
-{
-	{
-		"lo_open",
-		"$1::pg_catalog.oid, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lo_close",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_creat",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_create",
-		"$1::pg_catalog.oid",
-		1,
-		80100
-	},
-	{
-		"lo_unlink",
-		"$1::pg_catalog.oid",
-		1
-	},
-	{
-		"lo_lseek",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4",
-		3
-	},
-	{
-		"lo_lseek64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4",
-		3,
-		90300
-	},
-	{
-		"lo_tell",
-		"$1::pg_catalog.int4",
-		1
-	},
-	{
-		"lo_tell64",
-		"$1::pg_catalog.int4",
-		1,
-		90300
-	},
-	{
-		"lo_truncate",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2,
-		80300
-	},
-	{
-		"lo_truncate64",
-		"$1::pg_catalog.int4, $2::pg_catalog.int8",
-		2,
-		90300
-	},
-	{
-		"loread",
-		"$1::pg_catalog.int4, $2::pg_catalog.int4",
-		2
-	},
-	{
-		"lowrite",
-		"$1::pg_catalog.int4, $2::pg_catalog.bytea",
-		2
-	}
-};
-
-static int	lo_initialize(PGconn *conn);
 static Oid	lo_import_internal(PGconn *conn, const char *filename, Oid oid);
 
 static bool
@@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
 	mode = pg_hton32(mode);
 	argv[1] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_open", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(fd)))
 	{
@@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_close", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 80300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	len = pg_hton64(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	int			argFormats[] = {1, 1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
 	len = pg_hton32(len);
 	argv[1] = (char *) &len;
 
-	res = PQexecPrepared(conn, "libpq_internal_loread", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, -1))
 	{
@@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	/*
 	 * Long ago, somebody thought it'd be a good idea to declare this function
 	 * as taking size_t ... but the underlying backend function only accepts a
@@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
 
 	argv[1] = unconstify(char *, buf);
 
-	res = PQexecPrepared(conn, "libpq_internal_lowrite", 2,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
@@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "libpq_internal_lseek", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	PGresult   *res;
 	int64		retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	whence = pg_hton32(whence);
 	argv[2] = (char *) &whence;
 
-	res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
 		memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval));
@@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	mode = pg_hton32(mode);
 	argv[0] = (char *) &mode;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return InvalidOid;
-
 	if (PQserverVersion(conn) < 80100)
 	{
 		libpq_append_conn_error(conn, "server does not support function \"%s\"",
@@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId)
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_create", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd)
 	int			argFormats[] = {1};
 	PGresult   *res;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	if (PQserverVersion(conn) < 90300)
 	{
 		libpq_append_conn_error(conn, "server does not support functions \"%s\"",
@@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd)
 	fd = pg_hton32(fd);
 	argv[0] = (char *) &fd;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId)
 	PGresult   *res;
 	int			retval;
 
-	if (lo_initialize(conn) < 0)
-		return -1;
-
 	lobjId = pg_hton32(lobjId);
 	argv[0] = (char *) &lobjId;
 
-	res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1,
-						 (const char *const *) argv, argLens, argFormats, 1);
+	res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL,
+					   (const char *const *) argv, argLens, argFormats, 1);
 
 	if (lo_result_is_valid(res, sizeof(retval)))
 	{
@@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
 
 	return result;
 }
-
-
-/*
- * lo_initialize
- *
- * Initialize for a new large-object operation on an existing connection.
- * Return 0 if OK, -1 on failure.
- *
- * If we haven't previously done so, we prepared statements for all the
- * functions that are required for large object operations.
- */
-static int
-lo_initialize(PGconn *conn)
-{
-	/* Nothing we can do with no connection */
-	if (conn == NULL)
-		return -1;
-
-	/* Since this is the beginning of a query cycle, reset the error state */
-	pqClearConnErrorState(conn);
-
-	/* Nothing else to do if we already prepared the statements */
-	if (conn->lobjprepared)
-		return 0;
-
-	for (int i = 0; i < lengthof(lobjfuncs); i++)
-	{
-		PGresult   *res;
-		ExecStatusType status;
-		PQExpBufferData pname;
-		PQExpBufferData pquery;
-
-		if (PQserverVersion(conn) < lobjfuncs[i].version)
-			continue;
-
-		initPQExpBuffer(&pname);
-		initPQExpBuffer(&pquery);
-
-		appendPQExpBuffer(&pname, "libpq_internal_%s",
-						  lobjfuncs[i].name);
-		appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)",
-						  lobjfuncs[i].name, lobjfuncs[i].args);
-
-		res = PQprepare(conn, pname.data, pquery.data,
-						lobjfuncs[i].nargs, NULL);
-		status = PQresultStatus(res);
-		if (res)
-			PQclear(res);
-
-		termPQExpBuffer(&pname);
-		termPQExpBuffer(&pquery);
-
-		if (status == PGRES_COMMAND_OK)
-			continue;
-
-		libpq_append_conn_error(conn, "query to prepare large object statements failed");
-		return -1;
-	}
-
-	conn->lobjprepared = true;
-	return 0;
-}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 9dd0f42b6b7..cf968f1519b 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -544,7 +544,6 @@ struct pg_conn
 	PGTernaryBool in_hot_standby;	/* in_hot_standby */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
-	bool		lobjprepared;	/* whether LO statements have been prepared */
 	pg_prng_state prng_state;	/* prng state for load balancing connections */
 
 
-- 
2.50.1 (Apple Git-155)


--NDf4SqMA2rj1ZNJ4--





^ permalink  raw  reply  [nested|flat] 682+ messages in thread


end of thread, other threads:[~2026-05-26 16:12 UTC | newest]

Thread overview: 682+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-08-04 08:14 [PATCH v5 1/3] Adding per backend commit and rollback counters Bertrand Drouvot <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>
2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox